<?php

namespace App\Trip\Orders\BookOrders\Train\Order;

use App\Models\Train\TrainOrders\TrainOrder;
use App\Trip\Orders\BookOrders\Params\AbstractOrderParam\AbstractSnapOrderParam;
use App\Trip\Orders\BookOrders\Params\AbstractParam\AbstractParam;
use App\Trip\Orders\BookOrders\Params\TrainParam;
use App\Trip\Orders\BookOrders\Train\Order\AbstractOrder\AbstractBuildOrderInfo;
use App\Trip\Orders\BookOrders\Train\Passengers\AbstractOrderPassenger\AbstractOrderPassengers;
use App\Trip\Orders\BookOrders\Train\Passengers\SnapOrderPassengers;
use App\Trip\Orders\BookOrders\Train\PriceDetails\AbstractPriceDetails\AbstractPriceDetails;
use App\Trip\Orders\BookOrders\Train\PriceDetails\SnapPriceDetails;
use App\Trip\Orders\BookOrders\Train\SelectedSeats\BuildSnapSelectedSeats;
use App\Trip\Orders\BookOrders\Train\TrainStationTicket;
use App\Trip\Orders\TripOrderState;
use App\Trip\Orders\TripType;
use Exception;
use JetBrains\PhpStorm\ArrayShape;

class SnapNewOrder extends AbstractBuildOrderInfo
{
    private array $max_seat;

    /**
     * @throws Exception
     */
    public function __construct(AbstractSnapOrderParam $order_param, AbstractParam $param)
    {
        $this->param           = $param;
        $this->order_param     = $order_param;
        $this->passenger_param = $param->getPassengersParam();
        $this->selected_seats  = new BuildSnapSelectedSeats($this->order_param->getSelectSeat());
    }

    /**
     * @throws Exception
     */
    #[ArrayShape([
        'channel_id'               => "int",
        'trip_id'                  => "string",
        'order_sn'                 => "string",
        'out_order_sn'             => "string",
        'user_id'                  => "string",
        'transfer_flag'            => "int",
        'trip_no'                  => "int",
        'order_service'            => "string",
        'online'                   => "int",
        'out_order_id'             => "string",
        'trip_type'                => "int",
        'order_state'              => "int",
        'order_snap_state'         => "int",
        'change_flag'              => "int",
        'order_amount'             => "float",
        'receivable'               => "float",
        'origin_order_need_refund' => "float",
        'train_info'               => "array",
        'passengers'               => "array",
        'price_details'            => "array",
        'selected_seats'           => "string",
        'snap_up'                  => "int",
        'alternative_seats'        => "string",
        'alternative_train_codes'  => "string",
        'alternative_train_dates'  => "string",
        'mobile'                   => "string",
        'snap_level'               => "int",
        'stop_time'                => "int",
        'seat_name'                => "string",
    ])] public function buildOrderInfo(): array
    {
        $priceDetailsBuilder = $this->priceDetailsBuilder();
        return [
            'channel_id'               => channel()?->getChannelId(),
            'trip_id'                  => $this->order_param->getTripId(),
            'order_sn'                 => $this->order_param->generateOrderSn(),
            'out_order_sn'             => $this->order_param->getOutOrderSn(),
            'user_id'                  => $this->param->getUserId(),
            'transfer_flag'            => $this->order_param->getTransferFlag(),
            'trip_no'                  => $this->order_param->getTripNo(),
            'order_service'            => $this->order_param->OrderService(),
            'online'                   => $this->order_param->getOnline(),
            'out_order_id'             => '',
            'trip_type'                => TripType::TRIP_TYPE_TRAIN,
            'order_state'              => TripOrderState::ORDER_STATE_WAITING_PAY,
            'order_snap_state'         => TripOrderState::ORDER_SNAP_STATE_WAITING_PAY,
            'change_flag'              => TripOrderState::ORDER_CHANGE_FLAG_NONE,
            'order_amount'             => $priceDetailsBuilder->getOrderAmount(),
            'receivable'               => $priceDetailsBuilder->getOrderAmount(),
            'origin_order_need_refund' => $priceDetailsBuilder->calcOriginNeedRefundAmount(),
            'train_info'               => $this->getTrainInfo(),
            'passengers'               => $priceDetailsBuilder->getPassengers(),
            'price_details'            => $priceDetailsBuilder->getPriceDetails(),
            "snap_up"                  => TripOrderState::ORDER_SNAP_UP,
            'selected_seats'           => (string)$this->selected_seats,
            "alternative_seats"        => json_encode($this->order_param->getAlternativeSeats(), JSON_UNESCAPED_UNICODE),
            "alternative_train_codes"  => json_encode($this->order_param->getAlternativeTrains(), JSON_UNESCAPED_UNICODE),
            "alternative_train_dates"  => json_encode($this->order_param->getAlternativeTrainDates(), JSON_UNESCAPED_UNICODE),
            'mobile'                   => $this->param->getMobile(),
            'snap_level'               => $this->order_param->getSnapParam()->getSnapLevel(),
            'stop_time'                => $this->order_param->getSnapParam()->getStopTime(),
            'seat_name'                => $this->max_seat['seat_name'],
        ];
    }

    /**
     * @throws Exception
     */
    public function priceDetailsBuilder(): AbstractPriceDetails
    {
        return new SnapPriceDetails($this);
    }

    /**
     * @throws Exception
     */
    public function getTrainInfo(): array
    {
        $this->max_seat = $this->getOrderParam()->getSnapData()->getMaxPriceBYAlternativeTrainsAndSeats();
        $train_station  = new TrainStationTicket(new TrainParam($this->max_seat));
        return $train_station->TrainInfo()->getTrainInfo();
    }

    public function getOriginOrderInfo(): ?TrainOrder
    {
        return null;
    }

    /**
     * @throws Exception
     */
    public function passengerBuilder(): AbstractOrderPassengers
    {
        return new SnapOrderPassengers($this);
    }

    protected function check(): void
    {
        // 啥都不做
    }
}